/*
 www.pipoisu.com
 Copyright (c) 2011. All rights reserved.

 File   : i2cmaster.cpp
 Author(s): Erez Raviv

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "MyI2C.h"

/*************************************************************************
 Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2cSetBitrate(unsigned int bitrateKHz)
{
	// initialize twi prescaler and bit rate
	// Prescaler Value = 1 - xem datasheet trang 245
	TWSR &= (0 << TWPS0) | (0 << TWPS1);	//	cbi(TWSR, TWPS0);	//	cbi(TWSR, TWPS1);
	// calculate bitrate division
	// SCL freq = F_CPU/(16 + 2 * TWBR * PrescalerValue)) = F_CPU/(16 + 2 * TWBR * 4^TWPS))
	// Xem thanh ghi TWPS
	// TWPS1 TWPS0 Prescaler Value
	//   0     0     1
	//   0     1     4
	//   1     0     16
	//   1     1     64
	TWBR = ((F_CPU / 1000L / bitrateKHz) - 16) / 2 / 1;
}

void i2c_init(void)
{
	// set i2c bit rate to 80KHz
	i2cSetBitrate(80L);	// nen chon 80kHz la on dinh nhat
	// enable twi module, acks, and twi interrupt
	//TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA);
	// enable TWI (two-wire interface)
	TWCR = (1<<TWEN);
}

/*************************************************************************	
 Issues a start condition and sends address and transfer direction.
 return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
	uint8_t  twst;
	// send START condition
	TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
	// wait until transmission completed
	while (!(TWCR & (1 << TWINT)));
	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ((twst != TW_START) && (twst != TW_REP_START)) return 1;
	// send device address
	TWDR = address;
	TWCR = (1 << TWINT) | (1 << TWEN);
	// wail until transmission completed and ACK/NACK has been received
	while (!(TWCR & (1 << TWINT)));
	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) return 1;
	return 0;
}/* i2c_start */

/*************************************************************************
 Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
  /* send stop condition */
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
	// wait until stop condition is executed and bus released
	while (TWCR & (1 << TWSTO));
}/* i2c_stop */

/*************************************************************************
 Send one byte to I2C device
 
 Input:  byte to be transfered
 Return:  0 write successful 
      1 write failed
*************************************************************************/
unsigned char i2c_write(unsigned char data)
{	
  uint8_t  twst;
	// send data to the previously addressed device
	TWDR = data;
	TWCR = (1 << TWINT) | (1 << TWEN);
	// wait until transmission completed
	while (!(TWCR & (1 << TWINT)));
	// check value of TWI Status Register. Mask prescaler bits
	twst = TW_STATUS & 0xF8;
	if (twst != TW_MT_DATA_ACK) return 1;
	return 0;
}/* i2c_write */

/*************************************************************************
 Read one byte from the I2C device, request more data from device
 Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
	TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
	while (!(TWCR & (1 << TWINT))); 
	return TWDR;
}/* i2c_readAck */

/*************************************************************************
 Read one byte from the I2C device, read is followed by a stop condition
 Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
	TWCR = (1 << TWINT) | (1 << TWEN);
	while (!(TWCR & (1 << TWINT)));
	return TWDR;
}/* i2c_readNak */

/*************************************************************************
 Write 1 byte to addr - use wait to make sure device is ready
*************************************************************************/
/*void i2cWrite(uint8_t addr, uint8_t reg, uint8_t val)
{
	i2c_start(addr + I2C_WRITE);
	i2c_write(reg);
	i2c_write(val);
	i2c_stop();
}*/

/*************************************************************************
 Read 1 byte to addr - use wait to make sure device is ready
*************************************************************************/
/*uint8_t i2cRead(uint8_t addr, uint8_t reg)
{
	i2c_start(addr + I2C_WRITE);
	i2c_write(reg);
	i2c_start(addr + I2C_READ);
	uint8_t ret = i2c_readNak();
	i2c_stop();
	return ret;
}*/

/*************************************************************************
 Make sure device is ready
*************************************************************************/
/*uint8_t i2cDeviceReady(uint8_t addr)
{
	uint8_t ret = i2c_start(addr + I2C_WRITE);
	i2c_stop();
	return (ret == 0);		// if ret==0 then device is ready
}*/
